package com.anjie.powerproject.schedule;

import com.anjie.powerproject.common.Result;
import com.anjie.powerproject.entity.GraphInfo;
import com.anjie.powerproject.entity.StationInfo;
import com.anjie.powerproject.service.GraphInfoService;
import com.anjie.powerproject.service.StationInfoService;
import com.anjie.powerproject.strategy.pojo.DayWeather;
import com.anjie.powerproject.strategy.service.WeatherForecastService;
import com.anjie.powerproject.strategy.utils.DateUtils;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping(value = "schedule/update_graph_time")
public class UpdateGraphTimeSchedule {
    private static final Logger logger = LoggerFactory.getLogger(UpdateGraphTimeSchedule.class);

    @Autowired
    GraphInfoService graphInfoService;

    @Autowired
    StationInfoService stationInfoService;

    @Autowired
    WeatherForecastService weatherForecastService;

    @PersistenceContext
    EntityManager entityManager;

    @RequestMapping(value = "execute")
    public Result<Void> excute() {
        try {
            scheduleTask();
            return Result.ok(null);
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            return Result.error(String.format("[%s]", ex.getMessage()));
        }
    }

    private int compareTo(Integer startM, Integer startD, Integer endM, Integer endD) {
        return (startM * 100 + startD) - (endM * 100 + endD);
    }

    private GraphInfo todayGraph(List<GraphInfo> graphInfos) {
        String[] nowMD = DateUtils.mdFormat.format(new Date()).split("-");
        Integer nowM = Integer.parseInt(nowMD[0]);
        Integer nowD = Integer.parseInt(nowMD[1]);

        GraphInfo target = null;
        for (GraphInfo graph : graphInfos) {
            // 获取图谱开始时间和结束时间
            String[] start = graph.getGraphStartTime().split("-");
            Integer startM = Integer.parseInt(start[0]);
            Integer startD = Integer.parseInt(start[1]);

            String[] end = graph.getGraphEndTime().split("-");
            Integer endM = Integer.parseInt(end[0]);
            Integer endD = Integer.parseInt(end[1]);

            // 如果开始时间大于结束时间
            if (compareTo(startM, startD, endM, endD) > 0) {
                if ((compareTo(startM, startD, nowM, nowD) <= 0 && compareTo(nowM, nowD, 12, 31) <= 0) ||
                        (compareTo(nowM, nowD, 12, 31) <= 0 && compareTo(nowM, nowD, endM, endD) <= 0)) {
                    target = graph;
                    break;
                }
            } else {
                if (compareTo(startM, startD, nowM, nowD) <= 0 && compareTo(nowM, nowD, endM, endD) <= 0) {
                    target = graph;
                    break;
                }
            }
        }

        return target;
    }

    private void scheduleTask() throws ParseException {
        logger.info("自动调节图谱时间定时任务启动");

        // 获取所有的图谱
        List<GraphInfo> graphInfos = graphInfoService.getAllGraphInfo();

        // 找到今天所使用的图谱，如果今天的图谱不随规则改变则什么也不做
        GraphInfo todayGraph = todayGraph(graphInfos);
        if (todayGraph.getUseRule() != 1) {
            return;
        }

        // 获取站点信息
        StationInfo stationInfo = stationInfoService.findStationInfoLimitFirst();
        if (stationInfo == null) {
            throw new RuntimeException("站点信息为空");
        }
        String areaCode = stationInfo.getCityCode();

        // 获取当地前5天加后10天的天气
        List<DayWeather> weathers = weatherForecastService.getForecastDayWeatherByAddrCode(areaCode);

        // 获取16天的最高温度
        Double[] highTems = weathers.stream().map(DayWeather::getTemphigh).toArray(Double[]::new);
        // 获取16天的最低温度
        Double[] lowTems = weathers.stream().map(DayWeather::getTemplow).toArray(Double[]::new);

        // 获取开始规则
        Integer startDayNum = todayGraph.getStartDayNum();
        Integer startLevel = todayGraph.getStartLevel();
        Integer startRels = todayGraph.getStartRels();
        Integer startTem = todayGraph.getStartTem();

        // 首先匹配开始规则:
        // startLevel == 1:最高温, startLevel == 2:最低温
        Double[] tems = lowTems;
        if (startLevel == 1) {
            tems = highTems;
        }
        // startRels == 1: 大于，startRels == 2: 小于
        int idx = 0;
        int count = 0;
        while (idx < tems.length) {
            if (startRels == 1) {
                if (tems[idx] >= startTem) {
                    count += 1;
                    if (count == startDayNum) {
                        break;
                    }
                } else {
                    count = 0;
                }
            } else {
                if (tems[idx] <= startTem) {
                    count += 1;
                    if (count == startDayNum) {
                        break;
                    }
                } else {
                    count = 0;
                }
            }
            idx += 1;
        }
        int startRes = -1;
        // 如果找到了匹配的日期
        if (count == startDayNum) {
            startRes = idx;
        }

        // 获取结束规则
        Integer endDayNum = todayGraph.getEndDayNum();
        Integer endLevel = todayGraph.getEndLevel();
        Integer endRels = todayGraph.getEndRels();
        Integer endTem = todayGraph.getEndTem();
        // 然后匹配结束规则
        if (endLevel == 1) {
            tems = highTems;
        } else {
            tems = lowTems;
        }
        idx = tems.length - 1;
        count = 0;
        while (idx > 0) {
            if (endRels == 1) {
                if (tems[idx] >= endTem) {
                    count += 1;
                    if (count == endDayNum) {
                        break;
                    }
                } else {
                    count = 0;
                }
            } else {
                if (tems[idx] <= endTem) {
                    count += 1;
                    if (count == endDayNum) {
                        break;
                    }
                } else {
                    count = 0;
                }
            }
            idx -= 1;
        }

        int endRes = -1;
        // 如果找到了匹配的日期
        if (count == endDayNum) {
            endRes = idx + count - 1;
        }

        // 检查结束规则匹配的日期是否在开始规则匹配的日期之后
        // 若是，则更新图谱使用天数
        if (endRes != -1 && startRes != -1 && startRes < endRes) {
            // 擦除在session中缓存的对象
            Session session = entityManager.unwrap(org.hibernate.Session.class);
            todayGraph.setGraphStartTime(DateUtils.mdFormat.format(weathers.get(startRes).getSdate()));
            todayGraph.setGraphEndTime(DateUtils.mdFormat.format(weathers.get(endRes).getSdate()));
            session.evict(todayGraph);

            graphInfoService.updateGraphInfo(todayGraph);
        }
    }
}
